<script lang="ts" setup>
import { ref, watch } from 'vue'

const list = defineModel<any[]>({ required: true })

const props = withDefaults(
  defineProps<{
    api: (params: object) => Promise<any>
    params?: object
    immediate?: boolean
    size?: number
    sizeKey?: string
    pageKey?: string
    listKey?: string
  }>(),
  {
    params: () => ({}),
    immediate: true,
    size: 20,
    sizeKey: 'pageSize',
    pageKey: 'pageNum',
    listKey: 'rows',
  }
)

const status = ref<'none' | 'loading' | 'empty' | 'error' | 'more' | 'end'>('none')
const current = ref(1)
const promiseDebounce = uni.$usePromiseDebounce()

props.immediate && init()
watch(() => props.params, init, { deep: true })

function init() {
  current.value = 1
  status.value = 'none'
  list.value = []
  scrolltolower()
}

async function scrolltolower() {
  if (status.value === 'loading' || status.value === 'end') return
  status.value = 'loading'
  const res = await promiseDebounce(props.api({
    [props.sizeKey]: props.size,
    [props.pageKey]: current.value,
    ...props.params,
  })).catch((err) => {
    if (err !== 'PromiseDebounce: canceled') {
      status.value = 'error'
    }
    return Promise.reject(err)
  })
  const data = res?.[props.listKey] || []
  list.value.push(...data)
  if (data.length === 0 && current.value === 1) {
    status.value = 'empty'
  } else if (data.length < props.size) {
    status.value = 'end'
  } else {
    status.value = 'more'
    current.value++
  }
}
</script>

<template>
  <scroll-view class="load-list" scroll-y @scrolltolower="scrolltolower">
    <slot />
    <view v-if="status === 'loading'" class="loading">
      <uni-load-more status="loading" :iconSize="18" />
    </view>
    <view v-if="status === 'empty'" class="empty">
      <image src="/static/svg/empty.svg" />
      <uni-load-more :contentText="{ contentdown: '暂无数据' }" />
    </view>
    <view v-if="status === 'error'" class="error" @click="scrolltolower">
      <uni-load-more :contentText="{ contentdown: '加载失败，点击重试' }" />
    </view>
    <view v-if="status === 'more'" class="more">
      <uni-load-more status="more" />
    </view>
    <view v-if="status === 'end'" class="end">
      <uni-load-more status="no-more" />
    </view>
  </scroll-view>
</template>

<style lang="scss" scoped>
.load-list {
  height: 100%;
}

.empty {
  padding-top: 200rpx;

  >image {
    display: block;
    margin: 0 auto;
    width: 400rpx;
    height: 400rpx;
  }
}
</style>
